﻿using AJWPFAdmin.Core;
using AJWPFAdmin.Core.Components.AJTable.ViewModels;
using AJWPFAdmin.Core.Components.ViewModels;
using AJWPFAdmin.Core.Components.Views;
using AJWPFAdmin.Core.Enums;
using AJWPFAdmin.Core.ExtensionMethods;
using AJWPFAdmin.Core.Models;
using AJWPFAdmin.Core.Models.EF.Tables;
using AJWPFAdmin.Core.Utils;
using AJWPFAdmin.Core.Validation;
using AJWPFAdmin.Services.AppointAPI;
using AJWPFAdmin.Services.EF;
using Masuit.Tools;
using Masuit.Tools.Core.Validator;
using Masuit.Tools.Systems;
using Microsoft.EntityFrameworkCore;
using Prism.Commands;
using Prism.Events;
using Prism.Services.Dialogs;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using Yitter.IdGenerator;
using static AJWPFAdmin.Core.ExceptionTool;

namespace EntranceGuardManager.Modules.Main.ViewModels
{
    public class DeviceFormViewModel : AnnotationValidationViewModel, IDialogAware
    {
        private string _dialogTitle;
        public string DialogTitle
        {
            get { return _dialogTitle; }
            set { SetProperty(ref _dialogTitle, value); }
        }

        private bool _loading;
        public bool Loading
        {
            get { return _loading; }
            set { SetProperty(ref _loading, value); }
        }

        private bool _synchronized;
        public bool Synchronized
        {
            get { return _synchronized; }
            set { SetProperty(ref _synchronized, value); }
        }

        private Device _form;


        private AJTableFormSchemaItemOptions _watchhouseId;
        [Display(Name = "所属出入口")]
        [Required(ErrorMessage = "{0}必填")]
        public AJTableFormSchemaItemOptions WatchhouseId
        {
            get { return _watchhouseId; }
            set
            {
                SetProperty(ref _watchhouseId, value);
                SaveCmd.RaiseCanExecuteChanged();
            }
        }

        private AJTableFormSchemaItemOptions _passagewayId;
        [Display(Name = "所属通道")]
        [Required(ErrorMessage = "{0}必填")]
        public AJTableFormSchemaItemOptions PassagewayId
        {
            get { return _passagewayId; }
            set
            {
                SetProperty(ref _passagewayId, value);
                SaveCmd.RaiseCanExecuteChanged();
            }
        }

        private string _code;
        [Display(Name = "编号")]
        [StringLength(50, ErrorMessage = "{0}超长:{1}")]
        public string Code
        {
            get { return _code; }
            set
            {
                SetProperty(ref _code, value);
                SaveCmd.RaiseCanExecuteChanged();
            }
        }

        private string _ip;
        [Display(Name = "IP地址")]
        [StringLength(50, ErrorMessage = "{0}超长:{1}")]
        public string IP
        {
            get { return _ip; }
            set
            {
                SetProperty(ref _ip, value);
                SaveCmd.RaiseCanExecuteChanged();
            }
        }

        private DeviceType _type;
        public DeviceType Type
        {
            get { return _type; }
            set
            {
                if (SetProperty(ref _type, value))
                {
                    OnlyMonitor = value == DeviceType.监控相机_海康;
                    EnableVideoCapture = value == DeviceType.车牌识别相机_臻识;
                }
            }
        }

        private WatchPositionType? _watchPosition;
        public WatchPositionType? WatchPosition
        {
            get { return _watchPosition; }
            set
            {
                SetProperty(ref _watchPosition, value);
            }
        }

        private SerialPortType _serialPort;
        public SerialPortType SerialPort
        {
            get { return _serialPort; }
            set
            {
                SetProperty(ref _serialPort, value);
                SaveCmd.RaiseCanExecuteChanged();
            }
        }

        private string _port;
        [Display(Name = "端口号")]
        [AJFormIntegerField(ErrorMessage = "端口号有误")]
        public string Port
        {
            get { return _port; }
            set
            {
                SetProperty(ref _port, value);
                SaveCmd.RaiseCanExecuteChanged();
            }
        }

        private bool _onlyMonitor;
        public bool OnlyMonitor
        {
            get { return _onlyMonitor; }
            set
            {
                SetProperty(ref _onlyMonitor, value);
                SaveCmd.RaiseCanExecuteChanged();
                if (value)
                {
                    EnableVideoCapture = false;
                }
            }
        }

        private bool _enableVideoCapture;
        public bool EnableVideoCapture
        {
            get { return _enableVideoCapture; }
            set
            {
                SetProperty(ref _enableVideoCapture, value);
                SaveCmd.RaiseCanExecuteChanged();
                if (!value)
                {
                    VideoDuration = 0;
                    AutoVideoCaptureINValue = string.Empty;
                }
            }
        }

        private double _videoDuration;
        public double VideoDuration
        {
            get { return _videoDuration; }
            set
            {
                SetProperty(ref _videoDuration, value);

            }
        }

        private string _autoVideoCaptureINValue;
        public string AutoVideoCaptureINValue
        {
            get { return _autoVideoCaptureINValue; }
            set
            {
                SetProperty(ref _autoVideoCaptureINValue, value);

            }
        }

        private string _loginName;
        [Display(Name = "登录账号")]
        [StringLength(50, ErrorMessage = "{0}超长:{1}")]
        public string LoginName
        {
            get { return _loginName; }
            set
            {
                SetProperty(ref _loginName, value);
            }
        }

        private string _loginPassword;
        [Display(Name = "登录密码")]
        [StringLength(100, ErrorMessage = "{0}超长:{1}")]
        public string LoginPassword
        {
            get { return _loginPassword; }
            set
            {
                SetProperty(ref _loginPassword, value);
            }
        }

        private string _name;
        /// <summary>
        /// 名称
        /// </summary>
        [Display(Name = "名称")]
        [MaxLength(20, ErrorMessage = "{0}超长:{1}")]
        [Required(ErrorMessage = "{0}必填")]
        public string Name
        {
            get { return _name; }
            set
            {
                SetProperty(ref _name, value);
                SaveCmd.RaiseCanExecuteChanged();
            }
        }

        private string _devNo;
        /// <summary>
        /// 名称
        /// </summary>
        [Display(Name = "设备SN号")]
        [MaxLength(100, ErrorMessage = "{0}超长:{1}")]
        [Required(ErrorMessage = "{0}必填")]
        public string DevNo
        {
            get { return _devNo; }
            set
            {
                SetProperty(ref _devNo, value);
                SaveCmd.RaiseCanExecuteChanged();
            }
        }

        private string _videoPlayRTSPUrl;
        [Display(Name = "RTSP视频播放地址")]
        public string VideoPlayRTSPUrl
        {
            get { return _videoPlayRTSPUrl; }
            set
            {
                SetProperty(ref _videoPlayRTSPUrl, value);
            }
        }

        private string _videoPlayBackRTSPUrl;
        [Display(Name = "RTSP视频回放地址")]
        public string VideoPlayBackRTSPUrl
        {
            get { return _videoPlayBackRTSPUrl; }
            set
            {
                SetProperty(ref _videoPlayBackRTSPUrl, value);
            }
        }

        private bool _enableIO2Alarm;
        /// <summary>
        /// 是否启用IO2报警, 目前仅针对臻识有效
        /// </summary>
        public bool EnableIO2Alarm { get => _enableIO2Alarm; set => SetProperty(ref _enableIO2Alarm, value); }

        private int _io2AlarmDelaySeconds;
        /// <summary>
        /// IO2报警延迟秒数,目前仅针对臻识有效
        /// </summary>
        [AJFormIntegerField(ErrorMessage = "IO2报警延迟秒数有误")]
        public int IO2AlarmDelaySeconds
        {
            get => _io2AlarmDelaySeconds;
            set => SetProperty(ref _io2AlarmDelaySeconds, value);
        }

        private ObservableCollection<AJTableFormSchemaItemOptions> _watchHouseOptions;
        public ObservableCollection<AJTableFormSchemaItemOptions> WatchHouseOptions
        {
            get { return _watchHouseOptions; }
            set
            {
                SetProperty(ref _watchHouseOptions, value);
            }
        }

        private ObservableCollection<AJTableFormSchemaItemOptions> _passagewayOptions;
        public ObservableCollection<AJTableFormSchemaItemOptions> PassagewayOptions
        {
            get { return _passagewayOptions; }
            set
            {
                SetProperty(ref _passagewayOptions, value);
            }
        }

        private ObservableCollection<AJTableFormSchemaItemOptions> _passagewaySource;

        private Dictionary<string, DeviceType> _typeOptions;
        public Dictionary<string, DeviceType> TypeOptions
        {
            get { return _typeOptions; }
            set
            {
                SetProperty(ref _typeOptions, value);
            }
        }

        private Dictionary<string, SerialPortType> _serialPortOptions;
        public Dictionary<string, SerialPortType> SerialPortOptions
        {
            get { return _serialPortOptions; }
            set
            {
                SetProperty(ref _serialPortOptions, value);
            }
        }

        private Dictionary<string, WatchPositionType> _watchPositionOptions;
        public Dictionary<string, WatchPositionType> WatchPositionOptions
        {
            get { return _watchPositionOptions; }
            set
            {
                SetProperty(ref _watchPositionOptions, value);
            }
        }

        private DelegateCommand _resetSyncStatusCmd;
        public DelegateCommand ResetSyncStatusCmd =>
            _resetSyncStatusCmd ?? (_resetSyncStatusCmd = new DelegateCommand(ExecuteResetSyncStatusCmd));

        void ExecuteResetSyncStatusCmd()
        {
            if (MessageBox.Show("请确保台账方不存在此数据,重置后会重新上传至台账", "提示", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
            {
                _form.Synchronized = Synchronized = false;

                MessageBox.Show("请确保数据无误后点击 [保存] 按钮上传至台账", "已重置同步标记", MessageBoxButton.OK);
            }
        }

        private DelegateCommand<object> _watchhouseChangedCmd;
        public DelegateCommand<object> WatchhouseChangedCmd =>
            _watchhouseChangedCmd ?? (_watchhouseChangedCmd = new DelegateCommand<object>(ExecuteWatchhouseChangedCmd));

        void ExecuteWatchhouseChangedCmd(object parameter)
        {
            AJTableFormSchemaItemOptions options = null;

            if (parameter is AJTableFormSchemaItemOptions)
            {
                options = parameter as AJTableFormSchemaItemOptions;
            }
            else if (parameter is SelectionChangedEventArgs e)
            {
                e.Handled = true;
                if (e.AddedItems.Count > 0)
                {
                    options = e.AddedItems[0] as AJTableFormSchemaItemOptions;
                }
            }
            if (options != null)
            {
                PassagewayOptions = new ObservableCollection<AJTableFormSchemaItemOptions>(_passagewaySource.Where(p => ((Passageway)p.OtherData).WatchhouseId == (long)options.Value).ToList());

                //PassagewayId = PassagewayOptions.FirstOrDefault();
            }

        }

        private DelegateCommand _saveCmd;
        public DelegateCommand SaveCmd =>
            _saveCmd ?? (_saveCmd = new DelegateCommand(ExecuteSaveCmdAsync, CanExecuteSaveCmd));

        async void ExecuteSaveCmdAsync()
        {
            if (!ValidateModel())
            {
                SaveCmd.RaiseCanExecuteChanged();

                AJCommonDialog.ShowDialog(new AJCommonDialogViewModel.AJCommonDialogParams
                {
                    Title = "提示",
                    Message = "表单校验失败,请检查所填数据",
                    Detail = string.Join(";", ValidationErrorsByProperty.SelectMany(p => p.Value).Select(p => p.ToString()))
                });
                return;
            }

            if (OnlyMonitor && WatchPosition == null)
            {
                AJCommonDialog.ShowDialog(new AJCommonDialogViewModel.AJCommonDialogParams
                {
                    Title = "提示",
                    Message = "监控部位未设置",
                });
                return;
            }

            if (Type == DeviceType.车牌识别相机_臻识 && EnableIO2Alarm && IO2AlarmDelaySeconds <= 0)
            {
                AJCommonDialog.ShowDialog(new AJCommonDialogViewModel.AJCommonDialogParams
                {
                    Title = "提示",
                    Message = "IO2报警延迟秒数有误",
                });
                return;
            }

            Loading = true;

            var code = Code;
            var type = Type;
            _form.IP = IP;
            var wid = (long)WatchhouseId.Value;
            var psgId = (long)PassagewayId.Value;
            _form.LoginName = LoginName;
            _form.Name = Name;
            _form.LoginPassword = LoginPassword;
            _form.OnlyMonitor = OnlyMonitor;
            _form.EnableVideoCapture = EnableVideoCapture;
            _form.AutoVideoCaptureINValue = AutoVideoCaptureINValue;
            _form.VideoDuration = VideoDuration;
            _form.Port = Port.TryGetInt();
            _form.SerialPort = SerialPort;
            _form.WatchPosition = WatchPosition;
            _form.DevNo = DevNo;
            _form.EnableIO2Alarm = EnableIO2Alarm;
            _form.IO2AlarmDelaySeconds = IO2AlarmDelaySeconds;
            _form.VideoPlayRTSPUrl = VideoPlayRTSPUrl;
            _form.VideoPlayBackRTSPUrl = VideoPlayBackRTSPUrl;
            var addMode = _form.Id == 0;
            if (addMode)
            {
                _form.Type = type;
                _form.Code = code;
                _form.WatchhouseId = wid;
                _form.PassagewayId = psgId;
                if (db.Devices.Any(p => p.Code == code && p.Type == type
                && p.PassagewayId == psgId && p.WatchhouseId == wid))
                {
                    FriendlyError("编号已存在");
                }
                _form.Id = YitIdHelper.NextId();
                _form.CreateDate = DateTime.Now;
                db.Devices.Add(_form);
            }
            else
            {
                if ((_form.Code != code || _form.Type != type
                    || _form.WatchhouseId != wid || _form.PassagewayId != psgId)
                    && db.Devices.Any(p => p.Code == code && p.Type == type
                    && p.PassagewayId == psgId && p.WatchhouseId == wid))
                {
                    FriendlyError("编号已存在");
                }
                _form.Code = code;
                _form.Type = type;
                _form.WatchhouseId = wid;
                _form.PassagewayId = psgId;
                _form.UpdateDate = DateTime.Now;
                db.Entry(_form).State = EntityState.Modified;
            }

            await db.SaveChangesAsync();

            ProcessResult uploadResult = null;

            if (_appointSvc.API.Config.Key == SystemConfigKey.APIQingDao ||
                _appointSvc.API.Config.Key == SystemConfigKey.APIChengDu)
            {
                uploadResult = await UploadDeviceInfoAsync();
            }
            else if (_form.OnlyMonitor)
            {
                uploadResult = await UploadDeviceInfoAsync();
            }

            if (uploadResult != null && !uploadResult.Success)
            {
                Loading = false;
                return;
            }

            Loading = false;

            RequestClose?.Invoke(new DialogResult(ButtonResult.OK));
        }

        private async Task<ProcessResult> UploadDeviceInfoAsync()
        {
            var result = await _appointSvc.API.UploadDeviceInfoAsync(new DeviceInfoParams
            {
                Device = _form,
                Passageway = PassagewayOptions.FirstOrDefault(p => (long)p.Value == _form.PassagewayId).OtherData as Passageway,
                Watchhouse = WatchHouseOptions.FirstOrDefault(p => (long)p.Value == _form.WatchhouseId).OtherData as Watchhouse,
                Operation = !_form.Synchronized ? DataOperationType.新增 : DataOperationType.更新
            });
            if (!result.Success)
            {
                AJCommonDialog.ShowDialog(new AJCommonDialogViewModel.AJCommonDialogParams
                {
                    Title = $"{_appointSvc.API.KeyDescription} 设备信息同步接口提示",
                    Message = result.Message,
                    Detail = result.Data is Exception ex ? ex.StackTrace : string.Empty
                });
            }
            else
            {
                //必须重新查出来保存, 否则报并发错误
                var dbRecord = db.Devices.FirstOrDefault(p => p.Id == _form.Id);
                dbRecord.Synchronized = true;
                dbRecord.UpdateDate = DateTime.Now;
                db.Entry(dbRecord).State = EntityState.Modified;
                db.SaveChanges();
            }

            return result;

        }

        bool CanExecuteSaveCmd()
        {
            return !HasErrors;
        }

        public string Title => string.Empty;

        public event Action<IDialogResult> RequestClose;

        public bool CanCloseDialog()
        {
            return true;
        }

        public void OnDialogClosed()
        {

        }

        public async void OnDialogOpened(IDialogParameters parameters)
        {
            parameters.TryGetValue<Device>("data", out var data);

            var watchhouseSource = await db.Watchhouses.AsNoTracking().OrderBy(p => p.Id).ToListAsync();

            WatchHouseOptions = new ObservableCollection<AJTableFormSchemaItemOptions>(watchhouseSource.Select(p => new AJTableFormSchemaItemOptions
            {
                Label = p.Name,
                Value = p.Id,
                OtherData = p
            }));

            var passagewaySource = await db.Passageways.AsNoTracking().OrderBy(p => p.Id).ToListAsync();

            _passagewaySource = new ObservableCollection<AJTableFormSchemaItemOptions>(passagewaySource.Select(p => new AJTableFormSchemaItemOptions
            {
                Label = p.Name,
                Value = p.Id,
                OtherData = p

            }));

            if (data != null)
            {
                _form = data;
                Code = _form.Code;
                IP = _form.IP;
                LoginName = _form.LoginName;
                LoginPassword = _form.LoginPassword;
                OnlyMonitor = _form.OnlyMonitor;
                EnableVideoCapture = _form.EnableVideoCapture;
                VideoDuration = _form.VideoDuration.GetValueOrDefault();
                AutoVideoCaptureINValue = _form.AutoVideoCaptureINValue;
                Port = _form.Port.ToString();
                SerialPort = _form.SerialPort;
                Type = _form.Type;
                WatchhouseId = WatchHouseOptions.FirstOrDefault(p => (long)p.Value == _form.WatchhouseId);
                PassagewayId = _passagewaySource.FirstOrDefault(p => ((Passageway)p.OtherData).Id == _form.PassagewayId);
                Name = _form.Name;
                WatchPosition = _form.WatchPosition;
                Synchronized = _form.Synchronized;
                DevNo = _form.DevNo;
                IO2AlarmDelaySeconds = _form.IO2AlarmDelaySeconds;
                EnableIO2Alarm = _form.EnableIO2Alarm;
                VideoPlayRTSPUrl = _form.VideoPlayRTSPUrl;
                VideoPlayBackRTSPUrl = _form.VideoPlayBackRTSPUrl;
            }
            else
            {
                WatchhouseId = WatchHouseOptions.FirstOrDefault();
                Type = DeviceType.车牌识别相机_臻识;
                Code = string.Empty;
            }

            ExecuteWatchhouseChangedCmd(WatchhouseId);

            DialogTitle = data == null ? $"新增设备" : $"编辑 {data.Name}";
        }

        private DbService db;
        private AJGlobalExceptionResolvedEvent _globalExceptionEvt;
        private AppointAPISvc _appointSvc;

        public DeviceFormViewModel(DbService dbIns, AppointAPISvc appointAPISvc, IEventAggregator eventAggregator)
        {
            _form = new Device();
            _appointSvc = appointAPISvc;
            _globalExceptionEvt = eventAggregator.GetEvent<AJGlobalExceptionResolvedEvent>();
            _globalExceptionEvt.Subscribe(() =>
            {
                Loading = false;
            });
            db = dbIns;
            TypeOptions = CommonUtil.EnumToDictionary<DeviceType>(null);
            SerialPortOptions = CommonUtil.EnumToDictionary<SerialPortType>(null);
            WatchPositionOptions = CommonUtil.EnumToDictionary<WatchPositionType>(null);
            DialogTitle = string.Empty;
        }
    }

    public class DeviceTypeToFormItemVisibileConverter : IValueConverter
    {
        public bool VisibleWhenEqualParameter { get; set; }

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var result = false;
            if (value is DeviceType left && parameter is DeviceType right)
            {
                result = VisibleWhenEqualParameter ? left == right : left != right;
            }
            return result ? Visibility.Visible : Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return null;
        }
    }
}
